﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace MMMaze
{

    public class LayerGroup
    {
        public List<Wall> LeftWingPanels { get; set; }
        public List<Wall> RightWingPanels { get; set; }
        public Wall CenterWall { get; set; }
        public List<Wall> LeftBladePanels { get; set; }
        public List<Wall> RightBladePanels { get; set; }
        private PanelMatrix PM { get; set; }
        public int TotalLayers { get; set; }
        public int LayerIndex { get; set; }
        public LayerGroup(int WingCount, Func<Panel> PanelCreator, Func<Panel, Panel> PanelDecorator, PanelMatrix matrix, int totalLayers, int idx)
        {
                        TotalLayers = totalLayers  ;
                        LayerIndex = idx; 
            if (PanelCreator == null)
            {
                PanelCreator = Wall.DefaultPanelCreator;
            }

            if (PanelDecorator == null)
            {
                PanelDecorator = Wall.DefaultPanelDecorator;
            }

            LeftWingPanels = new List<Wall>(WingCount);
                        FillList(LeftWingPanels,
                    PanelCreator,
                    PanelDecorator,
                    (Panel PositionPanel, int index) =>
                        {
                            PositionPanel.Projection = new PlaneProjection { LocalOffsetX = -PositionPanel.Width * (index + 1) };
                            var mask = new LinearGradientBrush(null, 0);
                            mask.GradientStops.Add(new GradientStop() { Offset =(index + 1) +LayerIndex +1 , Color = Color.FromArgb(255, 0, 0, 0) });
                            mask.GradientStops.Add(new GradientStop() { Offset = (index - totalLayers + 1 + LayerIndex)+1, Color = Color.FromArgb(0, 0, 0, 0) });
                            PositionPanel.OpacityMask = mask; 
                        }
                    );


            RightWingPanels = new List<Wall>(WingCount);

                        FillList(RightWingPanels,
                    PanelCreator,
                    PanelDecorator,
                    (Panel PositionPanel, int index) => 
                        {
                            PositionPanel.Projection = new PlaneProjection { LocalOffsetX = PositionPanel.Width * (index + 1) };
                            var mask = new LinearGradientBrush(null, 0);
                            mask.GradientStops.Add(new GradientStop() { Offset = -(index + 1 + LayerIndex), Color = Color.FromArgb(255, 0, 0, 0) });
                            mask.GradientStops.Add(new GradientStop() { Offset = -(index - totalLayers + 1 + LayerIndex), Color = Color.FromArgb(0, 0, 0, 0) });
                            PositionPanel.OpacityMask = mask; 
                        }
                    );

            LeftBladePanels = new List<Wall>(WingCount);
            FillList(LeftBladePanels,
                    PanelCreator,
                    PanelDecorator,
                    (Panel PositionPanel, int index) => 
                        {
                            PositionPanel.Projection =
                            new PlaneProjection
                            {
                                RotationY = -90,
                                LocalOffsetX = -PositionPanel.Width / 2,
                                LocalOffsetZ = -PositionPanel.Width / 2 - index * PositionPanel.Width
                            };
                            var mask = new LinearGradientBrush(null, 0);
                            mask.GradientStops.Add(new GradientStop() { Offset = -(LayerIndex + 1 + index) + 1, Color = Color.FromArgb(255, 0, 0, 0) });
                            mask.GradientStops.Add(new GradientStop() { Offset = -(LayerIndex - totalLayers + 1 + index) + 1, Color = Color.FromArgb(0, 0, 0, 0) });
                            PositionPanel.OpacityMask = mask; 
                        }
                    );


            RightBladePanels = new List<Wall>(WingCount);
            FillList(RightBladePanels,
                    PanelCreator,
                    PanelDecorator,
                        (Panel PositionPanel, int index) => 
                        {
                            PositionPanel.Projection =
                            new PlaneProjection
                            {
                                RotationY = 90,
                                LocalOffsetX = PositionPanel.Width / 2,
                                LocalOffsetZ = -PositionPanel.Width / 2 - index * PositionPanel.Width
                            };
                            
                                var mask = new LinearGradientBrush  (null,0);
                                mask.GradientStops.Add(new GradientStop() { Offset = LayerIndex-totalLayers+1 +index , Color = Color.FromArgb(0, 0, 0, 0) });
                                mask.GradientStops.Add(new GradientStop() { Offset = LayerIndex + 1 + index, Color = Color.FromArgb(255, 0, 0, 0) });
                                PositionPanel.OpacityMask = mask; 
                        }
                    );

            CenterWall = new Wall()
            {
                CorePanel = PanelDecorator.Invoke(PanelCreator.Invoke()),
                Status = WallStatus.Normal,
                OrginalProjection = new PlaneProjection()
            };

            CenterWall.CorePanel.Projection = new PlaneProjection();
            CenterWall.CorePanel.Opacity = 1 - ((double)(LayerIndex+0.5) / (double)totalLayers);

            PM = matrix;
        }

        void FillList(List<Wall> list, Func<Panel> PanelCreator, Func<Panel, Panel> PanelDecorator, Action<Panel, int> position)
        {
            for (var i = 0; i < list.Capacity; i++)
            {
                var p = PanelDecorator.Invoke(PanelCreator.Invoke());
                p.Projection = new PlaneProjection();
              
                


                list.Add
                    (
                        new Wall
                        {
                            CorePanel = p,
                            OrginalProjection = ((PlaneProjection)p.Projection).Clone(),
                            Status = WallStatus.Normal
                        }
                    );
                position.Invoke(p, i);

            }

        }




        //public void AddTo(Panel Parent)
        //{
        //    foreach (var p in LeftWingPanels) Parent.Children.Add(p);
        //    foreach (var p in RightWingPanels) Parent.Children.Add(p);
        //    foreach (var p in LeftBladePanels) Parent.Children.Add(p);
        //    foreach (var p in RightBladePanels) Parent.Children.Add(p);
        //    Parent.Children.Add(CenterPanel);

        //}

        private List<Wall> _AllWalls;
        public List<Wall> AllWalls
        {
            get
            {
                if (_AllWalls == null)
                {


                    _AllWalls = new List<Wall>();
                    _AllWalls.Add(CenterWall);
                    _AllWalls.AddRange(RightWingPanels);
                    _AllWalls.AddRange(LeftWingPanels);
                    _AllWalls.AddRange(RightBladePanels);
                    _AllWalls.AddRange(LeftBladePanels);



                }
                return _AllWalls;
            }
            private set
            {
                AllWalls = value;

            }



        }



        double _GlobalOffsetX = 0;
        public double GlobalOffsetX
        {
            get
            {
                return _GlobalOffsetX;

            }
            set
            {

                _GlobalOffsetX = value;
                ChangeProperty((p, v) => ((PlaneProjection)p.Projection).GlobalOffsetX = v, _GlobalOffsetX);
            }
        }
        double _GlobalOffsetY = 0;
        public double GlobalOffsetY
        {
            get
            {
                return _GlobalOffsetY;

            }
            set
            {
                _GlobalOffsetY = value;
                ChangeProperty((p, v) => ((PlaneProjection)p.Projection).GlobalOffsetY = v, _GlobalOffsetY);
            }
        }
        double _GlobalOffsetZ = 0;
        public double GlobalOffsetZ
        {
            get
            {
                return _GlobalOffsetZ;

            }
            set
            {
                _GlobalOffsetZ = value;
                ChangeProperty((p, v) => ((PlaneProjection)p.Projection).GlobalOffsetZ = v, _GlobalOffsetZ);
            }
        }

        void ChangeProperty(Action<Panel, double> act, double value)
        {
            foreach (var wall in this.AllWalls)
            {
                act.Invoke(wall.CorePanel, value);
            }



        }


    }
}
